package com.iscas.imchat.sso;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.google.gson.Gson;
import com.iscas.imchat.utils.Util;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * Author: zhd
 * Data: 2022/6/1
 */

public class TokenGenerateHandler extends SimpleChannelInboundHandler<String> {

    private static final String Secret = "iscas_isrc_IM";
    private static final int expireInterval = 14;   // 14天过期

    private Util accountUtil;
    private Util tokenUtil;

    private static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    private static Map<String,Channel> channelMap = new HashMap<String,Channel>();

    public TokenGenerateHandler(Util databaseUtility, Util tokenUtility) {
        this.accountUtil = databaseUtility;
        this.tokenUtil = tokenUtility;
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        // 获取当前channel
        Channel channel = ctx.channel();
        TokenReqMessage returnMsg;

        // Read class
        Gson gson = new Gson();
        TokenReqMessage message = gson.fromJson(msg,TokenReqMessage.class);

        // 生成token
        if(message.getRequestType() == 1){
            System.out.println("接收到请求Token消息");

            // 检查账户存在
            String loginUid = message.getUid();
            String password = message.getPassword();
            List<HashMap<String, Object>> userList = this.accountUtil.Select("select * from account where uid='"
                    + loginUid + "' and password='"+password+"';");

            // 存在账户
            if(userList.size() != 0){
                // 检查是否已经生成token
                List<HashMap<String, Object>> tokenList = this.tokenUtil.Select(
                        "select * from token where uid='" + loginUid + "';");
                // JWT生成Token
                String token = genTokenFromUid(loginUid);
                if(tokenList.size() != 0){  //已经生成token，更新
                    // 缓存token
                    tokenUtil.Update("update token set token = '"+token+"' where uid = '"+loginUid+"';");
                }else {  // 还未生成token，创建
                    tokenUtil.Insert("insert into account (uid, token) values ('"
                            + loginUid + "', '" + token + "');");
                }
                // 返回token
                returnMsg = new TokenReqMessage(2, loginUid, "", token, 0);
                String output = new Gson().toJson(returnMsg);
                // 当前channel返回信息
                channel.writeAndFlush(output);
            }else {
                //不存在账户
                System.out.println("uid不存在或密码不正确");
                // 返回uid不存在信息
                returnMsg = new TokenReqMessage(2, loginUid,"", "", 1);
                String output = new Gson().toJson(returnMsg);
                // 当前channel返回信息
                channel.writeAndFlush(output);
            }
        }else{
            System.out.println("申请Token消息不合法");
        }
//         channel.close();
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        channels.add(channel);
        String key = channel.remoteAddress().toString();
        channelMap.put(key, channel);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        String key = ctx.channel().remoteAddress().toString();
        channelMap.remove(key);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }

    /**
     * uid生成Token
     * @param uid uid
     * @throws UnsupportedEncodingException
     */
    public static String genTokenFromUid(String uid) throws UnsupportedEncodingException {
        // 过期时间
        Calendar nowTime = Calendar.getInstance();
        nowTime.add(Calendar.DATE, TokenGenerateHandler.expireInterval);
        Date expiresDate = nowTime.getTime();

        // 参数
        Map<String, Object> map = new HashMap<>();
        map.put("alg", "HS256");
        map.put("typ", "JWT");


        Date iatDate = new Date();
        String token = JWT.create().withHeader(map) // header
                .withClaim("uid", uid) // payload
                .withIssuedAt(iatDate) // sign time
                .withExpiresAt(expiresDate) // expire time
                .sign(Algorithm.HMAC256(TokenGenerateHandler.Secret)); // signature

        return token;
    }
}
